package com.jgp.sys.controller;


import com.jgp.common.utils.JGPUtil;
import com.jgp.reporter.ReporterFormat;
import com.jgp.reporter.ReporterParam;
import com.jgp.sys.props.InvokeRemotePropBean;
import com.jgp.sys.service.ConfigService;
import com.jgp.sys.ui.GridResult;
import com.jgp.sys.ui.Pager;
import com.jgp.sys.ui.Result;
import com.jgp.sys.utils.DropUtil;
import com.jgp.sys.utils.ResultUtil;
import com.jgp.sys.utils.UrlUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Created by Gavin Lou on 16/3/14.
 */
public class JGPController {
    
    private static final Logger logger = LoggerFactory.getLogger(JGPController.class);
    
    @Autowired
    private ConfigService configService;
    
    @ModelAttribute
    public void common(Model model,Boolean editFlag) {
        if(Objects.nonNull(editFlag)){
            model.addAttribute("editFlag",editFlag);
        }else{
            model.addAttribute("editFlag",true);
        }
        model.addAttribute("globalConfig", configService.globalConfig());
    }
    
    protected String page(String page) {
        if (page.charAt(0) == '/') page = page.substring(1);
        return UrlUtil.getPageTemplateDirFromController(this.getClass()) + page;
    }
    
    /**
     * @param model       springMvc 模型数据
     * @param data        数据 Collection 或 Object[]
     * @param parameters  参数
     * @param tplFileName 报表模板名称
     * @param format      {@link ReporterFormat}
     * @return 报表视图
     */
    protected String jasperReporter(Model model, Object data, Map parameters, String tplFileName,
                                    ReporterFormat format) {
        /*model.addAttribute("data", data);
        model.addAttribute("parameters", parameters);
        model.addAttribute("template", tplFileName);
        model.addAttribute("format", format);*/
        ReporterParam param = new ReporterParam(data,parameters,tplFileName);
        List<ReporterParam> params = new ArrayList<>();
        params.add(param);
        return jasperMultiReporter( model, params,format);
    }
    
    protected String jasperReporter(Model model, ReporterParam param,
                                    ReporterFormat format) {
        List<ReporterParam> params = new ArrayList<>();
        params.add(param);
        return jasperMultiReporter( model, params,format);
    }
    
    protected String jasperMultiReporter(Model model, List<ReporterParam> params,
                                    ReporterFormat format) {
        model.addAttribute("params", params);
        model.addAttribute("format", format);
        return "jasper-multi-reporter";
    }
    
  /*  protected String jasperReporter(Model model, Object data, Map parameters, String tplFileName,
                                    ReporterFormat format) {
        model.addAttribute("data", data);
        model.addAttribute("parameters", parameters);
        model.addAttribute("template", tplFileName);
        model.addAttribute("format", format);
        return "jasper-reporter";
    }*/
    
    /**
     * 页面访问控制器--返回表单的初始化数据
     * 转换对象为前端组件需要的数据结构
     *
     * @param model  {@link Model}
     * @param alias  别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param object 对象
     */
    protected void re(Model model, String alias, Object object) {
        model.addAttribute(alias, object);
    }
    
    /**
     * 页面访问控制器--返回表单的初始化数据
     * 转换对象为前端组件需要的数据结构
     *
     * @param model  {@link Model}
     * @param alias  别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param object 对象
     */
    protected void reForm(Model model, String alias, Object... object) {
        model.addAttribute(alias, JGPUtil.toJson(ResultUtil.transform(object)));
    }
    
    /**
     * 页面访问控制器--返回列表的初始化数据
     * 转换对象为前端组件需要的数据结构
     *
     * @param model {@link Model}
     * @param alias 别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param cats  表头
     * @param list  列表数据
     */
    protected void reGrid(Model model, String alias, List<GridResult.Category> cats, List<?> list) {
        reGrid(model, alias, cats, list, null, null);
    }
    
    /**
     * 页面访问控制器--返回列表的初始化数据
     * 转换对象为前端组件需要的数据结构
     *
     * @param model        {@link Model}
     * @param alias        别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param cats         表头
     * @param list         列表数据
     * @param selectedKeys 默认选中的记录的id集合
     */
    protected void reGrid(Model model, String alias, List<GridResult.Category> cats, List<?> list, List<Object>
            selectedKeys) {
        reGrid(model, alias, cats, list, null, selectedKeys);
    }
    
    /**
     * 页面访问控制器--返回列表的初始化数据
     * 转换对象为前端组件需要的数据结构
     *
     * @param model {@link Model}
     * @param alias 别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param cats  表头
     * @param list  列表数据
     * @param pager 分页
     */
    protected void reGrid(Model model, String alias, List<GridResult.Category> cats, List<?> list, Pager pager) {
        reGrid(model, alias, cats, list, pager, null);
    }
    
    /**
     * 页面访问控制器--返回列表的初始化数据
     * 转换对象为前端组件需要的数据结构
     *
     * @param model        {@link Model}
     * @param alias        别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param cats         表头
     * @param list         列表数据
     * @param pager        分页
     * @param selectedKeys 默认选中的记录的id集合
     */
    protected void reGrid(Model model, String alias, List<GridResult.Category> cats, List<?> list, Pager pager,
                          List<Object> selectedKeys) {
        //model.addAttribute("globalConfig", configService.globalConfig());
        model.addAttribute(alias, JGPUtil.toJson(ResultUtil.transform(pager, cats, selectedKeys, list)));
    }
    
    /**
     * 设置返回成功标志
     *
     * @param flag 成功标志
     * @return 异步调用结果包装类
     */
    protected Result ajaxRe(Boolean flag) {
        return new Result(flag);
    }
    
    /**
     * 设置返回普通数据
     * 成功标志默认为true
     *
     * @param alias  别名
     * @param object 对象 直接将对象转为json结构 不进行前端组件数据结构转换
     * @return 异步调用结果包装类
     */
    protected Result ajaxReData(String alias, Object object) {
        return new Result(true).addData(alias, object);
    }
    
    /**
     * 设置返回前端组件表单数据，支持单表单多实体
     * 成功标志默认为true
     *
     * @param alias  别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param object 对象，可变长度参数，也就是可以传入多个对象，转换为前端组件需要的数据结构
     * @return 异步调用结果包装类
     */
    protected Result ajaxReForm(String alias, Object... object) {
        return new Result(true).addData(alias, JGPUtil.toJson(ResultUtil.transform(object)));
    }
    
    
    /**
     * 设置返回前端组件列表数据
     *
     * @param alias 别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param cats  表头
     * @param list  列表数据
     * @return 异步调用结果包装类
     */
    protected Result ajaxReGrid(String alias, List<GridResult.Category> cats, List<?> list) {
        return ajaxReGrid(alias, cats, list, null, null);
    }
    
    /**
     * 设置返回前端组件列表数据
     *
     * @param alias        别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param cats         表头
     * @param list         列表数据
     * @param selectedKeys 默认选中的记录的id集合
     * @return 异步调用结果包装类
     */
    protected Result ajaxReGrid(String alias, List<GridResult.Category> cats, List<?> list, List<Object>
            selectedKeys) {
        return ajaxReGrid(alias, cats, list, null, selectedKeys);
    }
    
    /**
     * 设置返回前端组件列表数据
     *
     * @param alias 别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param cats  表头
     * @param list  列表数据
     * @param pager 分页
     * @return 异步调用结果包装类
     */
    protected Result ajaxReGrid(String alias, List<GridResult.Category> cats, List<?> list, Pager pager) {
        return ajaxReGrid(alias, cats, list, pager, null);
    }
    
    /**
     * 设置返回前端组件列表数据
     *
     * @param alias        别名 即为前端调用的变量名 注意：这里有几个固定的别名，表单：fdata，表格gdata，下拉ldata
     * @param cats         表头
     * @param list         列表数据
     * @param pager        分页
     * @param selectedKeys 默认选中的记录的id集合
     * @return 异步调用结果包装类
     */
    protected Result ajaxReGrid(String alias, List<GridResult.Category> cats, List<?> list, Pager pager,
                                List<Object> selectedKeys) {
        return new Result(true)
                .addData(alias, JGPUtil.toJson(ResultUtil.transform(pager, cats, selectedKeys, list)));
    }
    
    
    /**
     * 获取用户ip地址
     *
     * @param request HttpServletRequest
     * @return 可能为多个ip 第一个为真实ip
     */
    public static String[] getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if (ip.equals("127.0.0.1")) {
                //根据网卡取本机配置的IP
                InetAddress ia = null;
                try {
                    ia = InetAddress.getLocalHost();
                    ip = ia.getHostAddress();
                } catch (UnknownHostException e) {
                    logger.error("无法确定主机的IP地址", e);
                    return null;
                }
            }
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ip != null && ip.length() > 15) {
            if (ip.indexOf(",") > 0) {
                ip = ip.substring(0, ip.indexOf(","));
                return StringUtils.split(ip, ",");
            }
        }
        return new String[]{ip};
    }
    
    
    protected Boolean ifInvokeFromRemote(InvokeRemotePropBean propBean){
        return DropUtil.ifInvokeFromRemote(propBean);
    }
    
}
